// internal/services/auth_service.go
package services

import (
	"fmt"
	"mygin/config"
	"mygin/internal/models"
	"mygin/internal/repositories"
	"time"

	"github.com/golang-jwt/jwt/v5"
	"golang.org/x/crypto/bcrypt"
)

type AuthService interface {
	GenerateTokens(user *models.User) (accessToken, refreshToken string, err error)        //生成令牌
	RefreshTokens(refreshToken string) (newAccessToken, newRefreshToken string, err error) //刷新令牌
	ValidateToken(tokenString string) (*jwt.RegisteredClaims, error)
	FindByUsername(username string) (*models.User, error)
	FindByTel(username string) (*models.User, error)
	CreateUser(username, password, tel string) (*models.User, error)
}

type authService struct {
	jwtCfg *config.JWTConfig
	repo   repositories.AuthRepository
}

// func NewAuthService(cfg *config.JWTConfig) AuthService {
// 	return &authService{jwtCfg: cfg}
// }

func NewAuthService(
	cfg *config.JWTConfig,
	repo repositories.AuthRepository, // 添加仓库参数
) AuthService {
	return &authService{
		jwtCfg: cfg,
		repo:   repo, // 初始化仓库
	}
}

// 生成令牌
func (s *authService) GenerateTokens(user *models.User) (string, string, error) {
	accessClaims := jwt.RegisteredClaims{
		Subject:   user.Username,
		ExpiresAt: jwt.NewNumericDate(time.Now().Add(s.jwtCfg.AccessDuration)),
		//ID:        user.ID.String(),
		ID: fmt.Sprintf("%d", user.ID),
	}

	accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
	accessSigned, err := accessToken.SignedString([]byte(s.jwtCfg.SecretKey))

	// 类似生成refresh token逻辑...
	refreshClaims := jwt.RegisteredClaims{
		ExpiresAt: jwt.NewNumericDate(time.Now().Add(s.jwtCfg.RefreshDuration)),
		ID:        fmt.Sprintf("%d|%s", user.ID, user.Username), // 复合标识
	}

	refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
	refreshSigned, err := refreshToken.SignedString([]byte(s.jwtCfg.SecretKey))
	if err != nil {
		return "", "", err
	}

	return accessSigned, refreshSigned, err
}

// 刷新令牌
func (s *authService) RefreshTokens(refreshToken string) (string, string, error) {
	// 验证refresh token
	claims, err := s.ValidateToken(refreshToken)
	if err != nil {
		return "", "", fmt.Errorf("invalid refresh token: %v", err)
	}

	// 从claims中提取用户信息
	userIDAndName := claims.ID
	var userID uint
	var username string
	_, err = fmt.Sscanf(userIDAndName, "%d|%s", &userID, &username)
	if err != nil {
		return "", "", fmt.Errorf("malformed token claims")
	}

	// 获取最新用户数据（确保用户仍存在且有效）
	user, err := s.repo.FindByUsername(username)
	if err != nil {
		return "", "", fmt.Errorf("user not found")
	}

	// 生成新令牌
	return s.GenerateTokens(user)
}

func (s *authService) ValidateToken(tokenString string) (*jwt.RegisteredClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &jwt.RegisteredClaims{},
		func(t *jwt.Token) (interface{}, error) {
			return []byte(s.jwtCfg.SecretKey), nil
		})

	if err != nil {
		return nil, err // 返回解析错误（如 Token 过期、格式错误等）
	}

	if token == nil || !token.Valid {
		return nil, fmt.Errorf("无效的令牌")
	}

	if claims, ok := token.Claims.(*jwt.RegisteredClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, err
}

func (s *authService) CreateUser(username, password, tel string) (*models.User, error) {
	// 1. 密码加密 (使用bcrypt)
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return nil, fmt.Errorf("failed to hash password: %v", err)
	}

	// 2. 创建用户模型
	newUser := &models.User{
		Username:  username,
		Password:  string(hashedPassword), // 存储加密后的密码
		Tel:       tel,
		CreatedAt: time.Now(),
	}

	// 3. 调用仓库层保存用户
	createdUser, err := s.repo.CreateUser(newUser)
	if err != nil {
		return nil, fmt.Errorf("failed to create user: %v", err)
	}

	// 4. 返回创建的用户(不包含密码)
	createdUser.Password = "" // 清空密码字段
	return createdUser, nil
}

func (s *authService) FindByUsername(username string) (*models.User, error) {
	return s.repo.FindByUsername(username)
}

func (s *authService) FindByTel(tel string) (*models.User, error) {
	return s.repo.FindByTel(tel)
}
